package com.jdb.loan.provider.service.impl;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.guns21.common.util.ObjectUtils;
import com.guns21.data.domain.JpaPageResult;
import com.guns21.result.domain.PageResult;
import com.guns21.result.domain.Result;
import com.guns21.support.service.BaseQueryService;
import com.guns21.support.util.WebUtils;
import com.jdb.loan.api.dto.LoanCategoryDTO;
import com.jdb.loan.api.dto.LoanDTO;
import com.jdb.loan.api.query.AmountCondition;
import com.jdb.loan.api.query.LoanQuery;
import com.jdb.loan.controller.assembler.LoanAssembler;
import com.jdb.loan.controller.assembler.LoanCategoryAssmbler;
import com.jdb.loan.provider.entity.LoanCategoryDO;
import com.jdb.loan.provider.entity.LoanDO;
import com.jdb.loan.provider.repository.LoanCategoryRepository;
import com.jdb.loan.provider.repository.LoanRepository;
import com.jdb.loan.provider.service.LoanQueryService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
public class LoanQueryServiceImpl extends BaseQueryService implements LoanQueryService {
    private static Logger logger = LoggerFactory.getLogger(LoanQueryServiceImpl.class);

    @Autowired
    private LoanRepository loanRepository;
    @Autowired
    private LoanCategoryRepository loanCategoryRepository;

    @Override
    public Result<LoanDTO> get(String id) {
        LoanDO one = loanRepository.getOne(id);
        LoanDTO loanDTO = LoanAssembler.toDTO(one);
        return Result.success(loanDTO);
    }

    @Override
    public PageResult<LoanDTO> list(Date time, boolean forward, int count, AmountCondition amount, String categoryId) {
        //TODO 使用JPA中的分页，默认会添加select count；需要进行优化

        Sort sort = new Sort(Sort.Direction.DESC, "updateTime");
        Pageable pageable = new PageRequest(0, count, sort);
        PredicateBuilder<LoanDO> loanDOPredicateBuilder = Specifications.<LoanDO>and()
                .lt(forward && Objects.nonNull(time), "updateTime", time)
                .gt(!forward && Objects.nonNull(time), "updateTime", time)
                .eq(StringUtils.isNotBlank(categoryId), "categoryId", categoryId);


        if (Objects.nonNull(amount)) {
            loanDOPredicateBuilder.predicate(Specifications.or()
                    // ----between
                    .between(amount.isMinAndMax(), "quotaMin", new Range<>(amount.getQuotaMin(), amount.getQuotaMax()))
                    .between(amount.isMinAndMax(), "quotaMax", new Range<>(amount.getQuotaMin(), amount.getQuotaMax()))
                    // ---- <
                    .le(amount.isMin(), "quotaMin", amount.getQuotaMin())
                    .le(amount.isMin(), "quotaMax", amount.getQuotaMin())
                    // ---- >
                    .ge(amount.isMax(), "quotaMin", amount.getQuotaMax())
                    .ge(amount.isMax(), "quotaMax", amount.getQuotaMax())
                    .build()
            );
        }

        Page<LoanDO> all = loanRepository.findAll(loanDOPredicateBuilder.build(), pageable);
        return JpaPageResult.success(all, loanDO -> {
            LoanDTO loanDTO = LoanAssembler.toDTO(loanDO);
            loanDTO.setCover(WebUtils.buildWebUrlWithFile(loanDTO.getCover()));
            return loanDTO;
        });
    }

    @Override
    public PageResult<LoanDTO> list(List<String> ids) {
        Specification<LoanDO> specification = Specifications.<LoanDO>and()
                .in(ObjectUtils.nonEmpty(ids), "id", ids)
                .build();
        return PageResult.success(loanRepository.findAll(specification), loanDO -> {
            LoanDTO loanDTO = LoanAssembler.toDTO(loanDO);
            return loanDTO;
        });
    }

    @Override
    public PageResult<LoanDTO> listByPage(LoanQuery loanQuery) {
//        Specification<LoanDTO> loanSpecification = (root, query, cb) -> {
//            ArrayList<Predicate> predicates = new ArrayList<>();
//
//            if (Objects.nonNull()) {
//                predicates.add(cb.in(root.get("loanAgency").get("id")).value(loanAgencyId));
//            }
//            if (!bailorId.isEmpty()) {
//                predicates.add(cb.in(root.get("bailor").get("id")).value(bailorId));
//            }
//            if (!status.isEmpty()) {
//                predicates.add(cb.in(root.get("status")).value(status));
//            }
//
//            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
//        };
        Pageable pageable = new PageRequest(loanQuery.getPage() - 1, loanQuery.getPageSize());
        Specification<LoanDO> specification = Specifications.<LoanDO>and()
                .eq(StringUtils.isNotBlank(loanQuery.getCategoryId()), "categoryId", loanQuery.getCategoryId())
//                .gt(Objects.nonNull(request.getAge()), "age", 18)
//                .between("birthday", new Range<>(new Date(), new Date()))
                .like(StringUtils.isNotBlank(loanQuery.getTitle()), "title", "%" + loanQuery.getTitle() + "%")
                .build();
        Page<LoanDO> all = loanRepository.findAll(specification, pageable);
        return JpaPageResult.success(all, loanDO -> LoanAssembler.toDTO(loanDO));
    }

    @Override
    public Result<LoanCategoryDTO> getLoanCategory(String id) {
        LoanCategoryDO one = loanCategoryRepository.getOne(id);
        return Result.success(LoanCategoryAssmbler.toDTO(one));
    }

    @Override
    public PageResult<LoanCategoryDTO> listCategories() {
        List<LoanCategoryDO> dtos = loanCategoryRepository.findAll();
        return PageResult.success(dtos, loanCategoryDO -> LoanCategoryAssmbler.toDTO(loanCategoryDO));
    }

}
